﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace Chisel.Core.Connections
{

	/// <summary>
	/// A segment that connects two anchors.
	/// </summary>
	public class Segment : UserControl
	{
		public Segment(Connection con)
			: base()
		{
			_connection = con;
		}


		private Connection _connection;

		/// <summary>
		/// The anchor at the start of the segment.
		/// </summary>
		public ISegmentEnd Start { get; set; }

		/// <summary>
		/// The anchor at the stop of the segment.
		/// </summary>
		public ISegmentEnd Stop { get; set; }

		/// <summary>
		/// The curret brush used to draw the foreground.
		/// </summary>
		private Brush ForeBrush
		{
			get { return _connection.ParentCanvas.StyleProvider.GetBrush(ActorType.Connection, BrushType.Foreground, _connection.State); }
		}

		/// <summary>
		/// Resets the style based on the canvas style provider.
		/// </summary>
		public void ResetStyle()
		{
			(Content as Shape).StrokeThickness = _connection.ParentCanvas.StyleProvider.ConnectionThickness;
			(Content as Shape).Stroke = ForeBrush;
		}

		/// <summary>
		/// Layout the segment in the connection canvas.
		/// </summary>
		public void Relayout()
		{
			// decide what to do based on connection style
			switch (_connection.ParentCanvas.StyleProvider.ConnectionStyle)
			{
				case ConnectionStyle.Diagonal:
					Line line;
					if (Content is Line)
						line = Content as Line;
					else
					{
						line = new Line();
						Content = line;
					}
					var p1 = Start.LocalPosition;
					line.X1 = p1.X;
					line.Y1 = p1.Y;
					var p2 = Stop.LocalPosition;
					line.X2 = p2.X;
					line.Y2 = p2.Y;
					break;

				case ConnectionStyle.Square:
					Polyline polyLine;
					if (Content is Polyline)
						polyLine = Content as Polyline;
					else
					{
						polyLine = new Polyline();
						Content = polyLine;
					}
					LayoutSquare(polyLine);
					break;

				case ConnectionStyle.Round:
					throw new NotImplementedException();
			}
			ResetStyle();
		}

		/// <summary>
		/// Perform the layout for a square connection.
		/// </summary>
		/// <remarks>This doesn't really need to be in a separate method, but it's just a lot of code, you know?</remarks>
		private void LayoutSquare(Polyline polyLine)
		{
			polyLine.Points.Clear();

			// add the start and stop points
			polyLine.Points.Add(Start.LocalPosition);
			polyLine.Points.Add(Stop.LocalPosition);

			if (Start.Direction != null && Stop.Direction == null)
			{
				var intersect = Start.LocalPosition.ClosestPoint((Point)Start.Direction, Stop.LocalPosition);
				polyLine.Points.Insert(1, intersect);
			}
			else if (Start.Direction == null && Stop.Direction != null)
			{
				Point intersect = Stop.LocalPosition.ClosestPoint((Point)Stop.Direction, Start.LocalPosition);
				polyLine.Points.Insert(1, intersect);
			}
			else if (Start.Direction != null && Stop.Direction != null && ((Point)Stop.Direction).Orientation() != ((Point)Stop.Direction).Orientation()) // the ends are perpendicular
			{
				Point intersect = PointHelper.Intersection(Start.LocalPosition, (Point)Start.Direction, Stop.LocalPosition, (Point)Stop.Direction);
				polyLine.Points.Insert(1, intersect);
			}
			else // the ends are parallel
			{
				if (((Point)Start.Direction).Orientation() == Orientation.Horizontal)
				{
					double midX = 0.5 * (Start.LocalPosition.X + Stop.LocalPosition.X);
					polyLine.Points.Insert(1, new Point(midX, Start.LocalPosition.Y));
					polyLine.Points.Insert(2, new Point(midX, polyLine.Points[2].Y));
				}
				else // vertical
				{
					double midY = 0.5 * (Start.LocalPosition.Y + Stop.LocalPosition.Y);
					polyLine.Points.Insert(1, new Point(Start.LocalPosition.X, midY));
					polyLine.Points.Insert(2, new Point(polyLine.Points[2].X, midY));
				}
			}
		}


		#region Mouse Interaction
		
		protected override void OnMouseEnter(MouseEventArgs e)
		{
			base.OnMouseEnter(e);
			_connection.OnRemoteMouseEnter(e);
		}

		protected override void OnMouseLeave(MouseEventArgs e)
		{
			base.OnMouseLeave(e);
			_connection.OnRemoteMouseLeave(e);
		}

		protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
		{
			base.OnMouseLeftButtonDown(e);
			_connection.OnRemoteMouseLeftButtonDown(e);
		}

		protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
		{
			base.OnMouseLeftButtonUp(e);
			_connection.OnRemoteMouseLeftButtonUp(e);
		}

		protected override void OnMouseMove(MouseEventArgs e)
		{
			base.OnMouseMove(e);
			_connection.OnRemoteMouseMove(e);
		}

		#endregion

	}
}
